#include <bson/bson.h>
#include <mongoc/mongoc.h>
#include <stdio.h>
#include "common.h"

int main (int argc, char *argv[]) {
	mongoc_client_t *client;
    mongoc_collection_t *collection;
    bson_error_t error;
    bson_oid_t oid;
    bson_t *doc;

    // conn
    mongoc_init ();
    client = mongoc_client_new ("mongodb://localhost:27017/?appname=insert-example-my");
    collection = mongoc_client_get_collection (client, "mydb", "mycoll");

	// insert doc
	doc = BCON_NEW(
		"ver", BCON_UTF8("v1.0"),
		"name", BCON_UTF8("test_libmongoc_my"),
		"train_id", BCON_INT32(1),
		"epoch", BCON_INT32(35),
		"parent_id", BCON_NULL,
		"lr", BCON_DOUBLE(0.001),
		"cost", BCON_DOUBLE(4.51),
		"datetime", BCON_DATE_TIME(current_timestamp()),
		"parent_epoch", BCON_NULL,
		"save_path", BCON_UTF8("/home/asuspei/PycharmProjects/AsusCondaP37tf24/python_ai/category/ml/mlp/_save/mnist_multi_classification.py/v1.0/mnist_multi_clf_by_numpynet_mlp_softmax_ok_1-10.npy"),
	    "acc", BCON_DOUBLE(0.89),
	    "acc_val", BCON_DOUBLE(0.77),
	    "cost_val", BCON_DOUBLE(5.23),
	    "tag", BCON_UTF8("First")
	);

#if 0
    if (!mongoc_collection_insert_one (
           collection, doc, NULL, NULL, &error)) {
        fprintf (stderr, "insert doc: %s\n", error.message);
    } else {
    	printf("Inserted the doc.\n");
    }
#endif

    // update doc
    if(!bson_append_int32(doc, "train_id", -1, 2)) {
        fprintf (stderr, "Append train_id failed.\n");
    }
    if(!bson_append_utf8(doc, "save_path", -1, "/xxx/yyy/zzz.index", -1)) {
        fprintf (stderr, "Append save_path failed.\n");
    }
    if(!bson_append_int32(doc, "parent_id", -1, 1)) {
        fprintf (stderr, "Append parent_id failed.\n");
    }
    if(!bson_append_null(doc, "acc", -1)) {  // acc => null
        fprintf (stderr, "Append acc failed.\n");
    }
    if(!bson_append_utf8(doc, "cost", -1, "Indefinite", -1)) {  // cost => utf8
        fprintf (stderr, "Append cost failed.\n");
    }
    if(!bson_append_int32(doc, "acc_val", -1, 90)) {  // acc_val double => int
        fprintf (stderr, "Append acc_val failed.\n");
    }
    if(!bson_append_date_time(doc, "datetime", -1, current_timestamp())) {
        fprintf (stderr, "Append datetime failed.\n");
    }
    if(!bson_append_utf8(doc, "tag", -1, "Modified", -1)) {
        fprintf (stderr, "Append tag failed.\n");
    }

    // insert the modified doc
#if 0
    if (!mongoc_collection_insert_one (
           collection, doc, NULL, NULL, &error)) {
        fprintf (stderr, "insert doc(mod): %s\n", error.message);
    } else {
    	printf("Inserted the modified doc.\n");
    }
#endif

	// clone
    size_t json_len = 0;
    char* json_str = bson_as_canonical_extended_json(doc, &json_len);
    printf("JSON: %s\n", json_str);
    bson_t * doc_copy = bson_new_from_json ((const uint8_t *)json_str, -1, &error);
    if (!doc_copy) {
      fprintf (stderr, "%s\n", error.message);
      return EXIT_FAILURE;
    } else {
    	printf("Cloned a doc from JSON.\n");
    }
    bson_free (json_str);

	// modify cloned doc
    if(!bson_append_utf8(doc_copy, "tag", -1, "Copied and Modified", -1)) {
        fprintf (stderr, "Append tag failed.\n");
    }
    if(!bson_append_double(doc, "acc_val", -1, 0.95)) {  // acc_val int => double
        fprintf (stderr, "Append acc_val failed.\n");
    }

    // insert the cloned doc and the ori doc
#if 0
    if (!mongoc_collection_insert_one (
           collection, doc_copy, NULL, NULL, &error)) {
        fprintf (stderr, "insert doc_copy: %s\n", error.message);
    } else {
    	printf("Inserted the cloned doc.\n");
    }
    if (!mongoc_collection_insert_one (
           collection, doc, NULL, NULL, &error)) {
        fprintf (stderr, "insert doc(mod): %s\n", error.message);
    } else {
    	printf("Inserted the cloning src doc again to make sure it is untouched.\n");
    }
#endif

    // get
    printf("Fetching ...\n");
    bson_t *query = BCON_NEW(
		"name", BCON_UTF8("test_libmongoc_my"),
/*		"train_id", "{", "$eq", BCON_INT32(1), "}",*/
		"train_id", BCON_INT32(2),
		"ver", BCON_UTF8("v1.0")
	);

//    bson_t *query = bson_new();
//    BSON_APPEND_UTF8 (query, "name", "test_libmongoc_my");
//    BSON_APPEND_INT32 (query, "train_id", 2);

    const bson_t *xi_doc;
    mongoc_cursor_t *cursor = mongoc_collection_find_with_opts (collection, query, NULL, NULL);

    int idx = 0;
	while (mongoc_cursor_next (cursor, &xi_doc)) {
	   json_str = bson_as_canonical_extended_json (xi_doc, NULL);
	   printf ("%d: %s\n", ++idx, json_str);
	   bson_free (json_str);
	   bson_destroy((bson_t*)xi_doc);
	}
	bson_destroy(query);

    // clean up
	printf("Clean up ...\n");
    bson_destroy (doc);
    bson_destroy (doc_copy);
    mongoc_collection_destroy (collection);
    mongoc_client_destroy (client);
    mongoc_cleanup ();

    printf("Done.\n");
    return 0;
}
